package com.google.code.mergeinformer.model;

import com.google.code.mergeinformer.util.StringUtils;
import org.hibernate.validator.constraints.NotBlank;

import javax.persistence.*;
import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import javax.validation.constraints.Size;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

/**
 * @author Dmitry Golubev
 */
@NamedQueries({
        @NamedQuery(name = "Project.getAll", query = "SELECT p FROM Project p ORDER BY p.name"),
        @NamedQuery(name = "Project.byShortName", query = "SELECT p FROM Project p WHERE p.shortName = :shortName"),
        @NamedQuery(name = "Project.isNameBusy", query = "SELECT COUNT(p) FROM Project p where p.name = :name"),
        @NamedQuery(name = "Project.isShortNameBusy", query = "SELECT COUNT(p) FROM Project p where p.shortName = :shortName")
})
@Entity
@Table(name = "project")
public class Project extends DefaultEntity {

    @NotBlank
    @Size(max = 64)
    @Column(name = "name", nullable = false, unique = true)
    private String name;

    @NotBlank
    @Size(max = 32)
    @Pattern(regexp = "^[0-9a-z!#$&-;=?\\[\\]_~-]+$", flags = Pattern.Flag.CASE_INSENSITIVE)
    @Column(name = "short_name", nullable = false, unique = true)
    private String shortName;

    @Valid
    @Embedded
    private VcsAttributes vcsAttributes;

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "project")
    @OrderBy("name")
    private Set<Task> tasks = new HashSet<>();

    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "project")
    private List<Branch> branches = new LinkedList<>();

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = StringUtils.normalize(name);
    }

    public String getShortName() {
        return shortName;
    }

    public void setShortName(String shortName) {
        this.shortName = StringUtils.normalize(shortName);
    }

    public VcsAttributes getVcsAttributes() {
        return vcsAttributes;
    }

    public void setVcsAttributes(VcsAttributes vcsAttributes) {
        this.vcsAttributes = vcsAttributes;
    }

    public Set<Task> getTasks() {
        return tasks;
    }

    public void addTask(Task task) {
        if (task != null) {
            tasks.add(task);
            task.setProject(this);
        }
    }

    public List<Branch> getBranches() {
        return branches;
    }

    public void replaceBranches(List<Branch> branches) {
        this.branches.clear();
        for (Branch branch : branches) {
            branch.setProject(this);
            // do not deep copy branches since they are immutable
            this.branches.add(branch);
        }
    }

    public Project copyAttributes(Project project) {
        name = project.name;
        shortName = project.shortName;
        vcsAttributes = new VcsAttributes(project.vcsAttributes);
        return this;
    }

    public int getFailedTasksCount() {
        int count = 0;
        for (Task task : tasks) {
            if (StringUtils.isNotBlank(task.getStackTrace())) {
                ++count;
            }
        }
        return count;
    }
}
